home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-11-17 | 12.2 KB | 451 lines | [TEXT/CWIE] |
- module: Main
-
- /*
- QD3ViewerMain.dyl
-
- QD3D Application example for Mindy Dylan.
-
- This demonstrates direct use of the Toolbox from Dylan.
- It is not a good example of how Dylan SHOULD be used.
-
- by Patrick C. Beard.
- */
-
- define library QD3D-Example
- use dylan;
- use format;
- use Toolbox;
- use QD3D;
- end library QD3D-Example;
-
- define module Main
- use dylan;
- use extensions, import: { main, <equal-table>, <boolean> };
- use threads; // imports "spawn-thread".
- use extern; // imports "<c-string>".
- use format, import: { format-to-string };
- use Toolbox; // imports "Debugger", etc.
-
- use QD3DTypes;
- use QD3DMath;
- use QD3DMisc;
- use QD3DViewer;
- end module Main;
-
- // menu constants.
-
- define constant $MenuBar-ID =128;
-
- define constant $Apple-Menu-ID = 128;
- define constant $About-Item = 1;
-
- define constant $File-Menu-ID = 129;
- define constant $New-Item = 1;
- define constant $Open-Item = 2;
- define constant $Close-Item = 3;
- define constant $Quit-Item = 5;
-
- define constant $Edit-Menu-ID = 130;
- define constant $Undo-Item = 1;
- define constant $Cut-Item = 3;
- define constant $Copy-Item = 4;
- define constant $Paste-Item = 5;
- define constant $Clear-Item = 6;
-
- define constant $Font-Menu-ID = 131;
-
- // alert & dialog constants.
-
- define constant $About-Alert-ID = 128;
- define constant $Document-Window-ID = 128;
- define constant $Cricket-snd-ID = 128;
-
- // main!
-
- define method main (argv0, #rest args)
- let menuBar = GetNewMBar($MenuBar-ID);
- if (menuBar ~= $nil)
- SetMenuBar(menuBar);
- FillMenu($Apple-Menu-ID, "DRVR");
- FillMenu($Font-Menu-ID, "FONT");
- DrawMenuBar();
- EventLoop();
- end if;
- end method main;
-
- define method FillMenu(menuID :: <integer>, typestr :: <string>)
- let menu = GetMenuHandle(menuID);
- if (menu ~= $nil)
- AppendResMenu(menu, os-type(typestr));
- end if;
- end method FillMenu;
-
- // get access to a C global that gets set when a "Quit" AppleEvent is received.
- define constant theTimeToQuit = find-c-pointer("theTimeToQuit");
- define constant collect-garbage = get-c-function("collect_garbage", args: #(), result: #());
- define constant $min-free-mem = 512 * 1024;
- define constant $untitled-name = as(<Pascal-string>, "Untitled Viewer");
-
- define method garbage-collector ()
- let cursor-handle = GetCursor(128);
- if (cursor-handle ~= $nil)
- HLockHi(cursor-handle);
- let cursor-ptr = pointer-at(cursor-handle);
- while (#t)
- if (FreeMem() < $min-free-mem)
- SetCursor(cursor-ptr);
- collect-garbage();
- SetCursor(qd.arrow);
- end if;
- end while;
- end if;
- end method garbage-collector;
-
- // create some support for dealing with QD3D matrices.
-
- define method make (class == <TQ3Matrix4x4>, #all-keys)
- as(<TQ3Matrix4x4>, NewPtr(content-size(<TQ3Matrix4x4>)));
- end method make;
-
- define method destroy (obj :: <TQ3Matrix4x4>) => ();
- DisposePtr(as(<Ptr>, obj));
- end method destroy;
-
- define class <Viewer-Document> (<object>)
- slot viewer-window :: <WindowPtr>, init-keyword: window:;
- slot viewer-object :: <TQ3ViewerObject>, init-keyword: viewer:;
- slot viewer-matrix :: <TQ3Matrix4x4>;
- end class <Viewer-Document>;
-
- define method initialize (self :: <Viewer-Document>, #next next-method, #key window, viewer)
- next-method();
- self.viewer-matrix := make(<TQ3Matrix4x4>);
- Q3Matrix4x4-SetIdentity(self.viewer-matrix);
- end method initialize;
-
- define method EventLoop () => ();
- // some variables we'll need.
- let event = make(<EventRecord>);
- let localWhere = point(0, 0);
- let itemString = make (<Pascal-string>);
- let mouseRgn = NewRgn();
- let oldClip = NewRgn();
- let newClip = NewRgn();
- RectRgn(mouseRgn, qd.screenBits.bounds);
- let textRect = make(<Rect>, bottom: 32, right: 100);
- let sizeRect = make(<Rect>, top: 100, left: 100, bottom: 1000, right: 1000);
- let viewer-documents = make(<equal-table>);
- let reply = make(<StandardFileReply>);
- let tempMatrix = make(<TQ3Matrix4x4>);
-
- /* let collector-thread = spawn-thread("garbage-collector", garbage-collector); */
-
- block (return)
- local method FrontDocument () => (window, viewer, document);
- let frontWindow = FrontWindow();
- let frontDoc = element(viewer-documents, frontWindow, default: #f);
- let frontViewer =
- if (frontDoc)
- frontDoc.viewer-object;
- else
- $nil;
- end if;
- values(frontWindow, frontViewer, frontDoc);
- end method;
-
- local method DrawClippedGrowIcon (window :: <WindowPtr>)
- GetClip(oldClip);
- let r = window.portRect;
- SetRectRgn(newClip, r.right - 15, r.bottom - 15, r.right, r.bottom);
- SetClip(newClip);
- DrawGrowIcon(window);
- SetClip(oldClip);
- end method;
-
- // draw window here.
- local method DrawViewer (window :: <WindowPtr>)
- SetPort(window);
- Q3ViewerDraw(viewer-documents[window].viewer-object);
- DrawClippedGrowIcon(window);
- end method;
-
- local method NewViewer ()
- let window = GetNewCWindow($Document-Window-ID);
- if (window ~= $nil)
- SetWTitle(window, $untitled-name);
- let viewer = Q3ViewerNew(window, window.portRect, $kQ3ViewerDefault);
- let document = make(<Viewer-Document>, window: window, viewer: viewer);
- viewer-documents[window] := document;
- ShowWindow(window);
- end if;
- end method;
-
- local method OpenViewer ()
- if (StandardGetFile(reply))
- let window = GetNewCWindow($Document-Window-ID);
- if (window ~= $nil)
- let spec = reply.sfFile;
- SetWTitle(window, spec.name);
- let viewer = Q3ViewerNew(window, window.portRect, $kQ3ViewerDefault);
- let document = make(<Viewer-Document>, window: window, viewer: viewer);
- viewer-documents[window] := document;
- // open the file.
- let (result, refNum) = FSpOpenDF(reply.sfFile, $fsRdPerm);
- if (result = $noErr)
- Q3ViewerUseFile(viewer, refNum);
- FSClose(refNum);
- end if;
- ShowWindow(window);
- end if;
- end if;
- end method;
-
- local method CloseViewer (window :: <WindowPtr>)
- let document = viewer-documents[window];
- viewer-documents := remove-key!(viewer-documents, window);
- Q3ViewerDispose(document.viewer-object);
- DisposeWindow(window);
- end method;
-
- local method DoAbout ()
- let sound = GetResource(os-type("snd "), $Cricket-snd-ID);
- if (sound ~= $nil)
- SndPlay($nil, sound, #f);
- ReleaseResource(sound);
- end if;
- Alert($About-Alert-ID);
- end method;
-
- // pre-process menu states.
- local method UpdateMenus ()
- let fileMenu = GetMenuHandle($File-Menu-ID);
- let editMenu = GetMenuHandle($Edit-Menu-ID);
- let fontMenu = GetMenuHandle($Font-Menu-ID);
- if (FrontWindow() ~= $nil)
- EnableItem(fileMenu, $Close-Item);
- EnableItem(editMenu, 0);
- EnableItem(fontMenu, 0);
- else
- DisableItem(fileMenu, $Close-Item);
- DisableItem(editMenu, 0);
- DisableItem(fontMenu, 0);
- end if;
- DrawMenuBar();
- end method;
-
- // process menu selections.
- local method DoMenu (menu, item)
- if (menu ~= 0 & item ~= 0)
- select (menu by \=)
- $Apple-Menu-ID =>
- if (item = $About-Item)
- DoAbout();
- else
- GetMenuItemText(GetMenuHandle($Apple-Menu-ID), item, itemString);
- OpenDeskAcc(itemString);
- end if;
- $File-Menu-ID =>
- select (item by \=)
- $New-Item =>
- NewViewer();
- $Open-Item =>
- OpenViewer();
- $Close-Item =>
- let window = FrontWindow();
- if (window ~= $nil)
- CloseViewer(window);
- end if;
- $Quit-Item =>
- return();
- end select;
- $Font-Menu-ID =>
- let window = FrontWindow();
- if (window ~= $nil)
- GetMenuItemText(GetMenuHandle($Font-Menu-ID), item, itemString);
- SetPort(window);
- TextFont(GetFNum(itemString));
- DrawViewer(window);
- end if;
- $Edit-Menu-ID =>
- let (frontWindow, frontViewer) = FrontDocument();
- if (frontViewer ~= $nil)
- select (item by \=)
- $Cut-Item =>
- Q3ViewerCut(frontViewer);
- $Copy-Item =>
- Q3ViewerCopy(frontViewer);
- $Paste-Item =>
- Q3ViewerPaste(frontViewer);
- $Clear-Item =>
- Q3ViewerClear(frontViewer);
- end select;
- end if;
- otherwise =>
- GetMenuItemText(GetMenuHandle(menu), item, itemString);
- DebugStr(itemString);
- end select;
- end if;
- HiliteMenu(0);
- UpdateMenus();
- end method;
-
- // process mouse clicks.
- local method DoClick (event :: <EventRecord>)
- let (partCode, window) = FindWindow(event-where(event));
- select (partCode)
- $inMenuBar =>
- UpdateMenus();
- let (menu, item) = MenuSelect(event-where(event));
- DoMenu(menu, item);
- $inDesk =>
- #f;
- $inDrag =>
- DragWindow(window, event-where(event));
- $inContent =>
- if (window ~= FrontWindow())
- SelectWindow(window);
- end if;
- $inGoAway =>
- if (TrackGoAway(window, event-where(event)))
- CloseViewer(window);
- UpdateMenus();
- end if;
- $inZoomIn, $inZoomOut =>
- if (TrackBox(window, event-where(event), partCode))
- SetPort(window);
- EraseRect(window.portRect);
- ZoomWindow(window, partCode, #t);
- Q3ViewerSetBounds(viewer-documents[window].viewer-object, window.portRect);
- end if;
- $inGrow =>
- let (height, width) = GrowWindow(window, event-where(event), sizeRect);
- if (height ~= 0 & width ~= 0)
- SetPort(window);
- SizeWindow(window, width, height, #f);
- EraseRect(window.portRect);
- DrawViewer(window);
- end if;
- otherwise =>
- #f;
- end select;
- end method;
-
- local method DoRotation (document :: <Viewer-Document>, forward :: <boolean>)
- // mess with the transformation matrix.
- let view = Q3ViewerGetView(document.viewer-object);
- let matrix = document.viewer-matrix;
-
- // multiply the matrix.
- Q3Matrix4x4-SetRotate-XYZ(tempMatrix, 0.1, 0.12, 0.08);
- Q3Matrix4x4-Multiply(matrix, tempMatrix, matrix);
-
- // re-render the view.
- SetPort(document.viewer-window);
- Q3ViewerDraw(document.viewer-object);
-
- Q3View-StartRendering(view);
- let renderStatus = $kQ3ViewStatusRetraverse;
- while (renderStatus = $kQ3ViewStatusRetraverse)
- Q3MatrixTransform-Submit(matrix, view);
- renderStatus := Q3View-EndRendering(view);
- end while;
- end method;
-
- // process keystrokes.
- local method DoKey (event :: <EventRecord>)
- let ch = as(<character>, logand(event-message(event), 255));
- if (logand(event-modifiers(event), $cmdKey) = $cmdKey)
- UpdateMenus();
- let (menu, item) = MenuKey(ch);
- DoMenu(menu, item);
- else
- let (frontWindow, frontViewer, frontDocument) = FrontDocument();
- if (frontDocument)
- select (ch)
- '+' =>
- DoRotation(frontDocument, #t);
- '-' =>
- DoRotation(frontDocument, #f);
- otherwise =>
- #f;
- end select;
- end if;
- end if;
- end method;
-
- // process update events.
- local method DoUpdate (event :: <EventRecord>)
- let window = as(<WindowPtr>, event-message(event));
- BeginUpdate(window);
- DrawViewer(window);
- EndUpdate(window);
- end method;
-
- // process activate events.
- local method DoActivate (event :: <EventRecord>)
- let window = as(<WindowPtr>, event-message(event));
- DrawViewer(window);
- end method;
-
- // get initial state right.
- UpdateMenus();
-
- // the event loop goes on until somebody quits.
- while (signed-long-at(theTimeToQuit) = 0)
- let (frontWindow, frontViewer) = FrontDocument();
- if (frontViewer ~= $nil)
- SetPort(frontWindow);
- GetMouse(localWhere);
- if (PtInRect(localWhere, frontWindow.portRect))
- Q3ViewerAdjustCursor(frontViewer, localWhere);
- else
- SetCursor(qd.arrow);
- end if;
- end if;
- if (WaitNextEvent($everyEvent, event, 5, mouseRgn))
- let what = event-what(event);
- let eventHandled =
- if (frontViewer ~= $nil & what ~= $updateEvt)
- Q3ViewerEvent(frontViewer, event);
- else
- #f;
- end if;
- if (~eventHandled)
- select (event-what(event))
- $mouseDown =>
- DoClick(event);
- $keyDown =>
- DoKey(event);
- $updateEvt =>
- DoUpdate(event);
- $activateEvt =>
- DoActivate(event);
- $osEvt =>
- SysBeep(1);
- $kHighLevelEvent =>
- let result = AEProcessAppleEvent(event);
- otherwise =>
- #f;
- end select;
- end if;
- end if;
- end while;
- cleanup
- destroy(event);
- destroy(itemString);
- DisposeRgn(mouseRgn);
- DisposeRgn(oldClip);
- DisposeRgn(newClip);
- destroy(textRect);
- destroy(sizeRect);
- destroy(reply);
- DisposePtr(as(<Ptr>, tempMatrix));
- for (document in viewer-documents)
- Q3ViewerDispose(document.viewer-object);
- DisposeWindow(document.viewer-window);
- destroy(document.viewer-matrix);
- end for;
- /* kill-thread(collector-thread); */
- end block;
- end method EventLoop;
-